var curgame,curuser,adapter,imgadapter;
var curwindow=0;
var readwin;
var waiting=false;
var linkwaiting=false;
var font3width,font3height,font4width,font4height;
var inlink=0;
var timer=null;
var pendingImages=[];

var windows=[];
var root;

var stylehints=[
	[],	// AllTypes
	[],	// Pair
	[],	// Blank
	[	// TextBuffer
		[0,0,0,0,0,0,1,'','',0],	// Normal
		[0,0,0,0,1,0,1,'','',0],	// Emphasized
		[0,0,0,0,0,0,0,'','',0],	// Preformatted
		[0,0,0,5,1,0,1,'','',0],	// Header
		[0,0,0,2,1,0,1,'','',0],	// Subheader
		[0,0,0,0,0,0,1,'#900','',0],	// Alert
		[0,0,0,0,0,1,1,'#090','',0],	// Note
		[40,0,0,0,0,0,1,'','',0],	// BlockQuote
		[0,0,0,0,1,0,1,'','',0],	// Input
		[0,0,0,0,0,0,1,'','',0],	// User1
		[0,0,0,0,0,0,1,'','',0]		// User2
	],
	[],	// TextGrid
	[]	// Graphics
];

function call(params)
{
	var p=[];
	p.push("game="+escape(curgame));
	p.push("user="+escape(curuser));
	for (var e in params)
	{
		if (typeof(params[e])=="string" || typeof(params[e])=="number")
			p.push(e+"="+escape(params[e]));
	}
	new Ajax.Request(adapter,{parameters:p.join('&'),onComplete:display});
}
function cleanup()
{
	call({	mode: "cleanup"});
	return true;
}

function run(cmd,imgcmd,game,user)
{
	window.onunload=cleanup;
	font4width=$('presize').offsetWidth;
	font4height=$('presize').offsetHeight;
	font3width=$('divsize').offsetWidth;
	font3height=$('divsize').offsetHeight;
	$('screen').removeChild($('sizetest'));

	adapter=cmd;
	imgadapter=imgcmd;
	curgame=game;
	curuser=user;
	$('input').focus();
	call({	mode: "start",
		width: $('screen').offsetWidth, 
		height: $('screen').offsetHeight,
		width3: font3width,
		height3: font3height,
		width4: font4width,
		height4: font4height});
}
function sendchar(e)
{
	if (timer!=null) clearTimeout(timer);
	timer=null;
	var key;
	if (e.keyCode)
	{
		key=e.keyCode;
		//map arrowkeys
		if (key==38) key=129;
		if (key==40) key=130;
		if (key==37) key=131;
		if (key==39) key=132;
	}
	else key=e.which;
	call({	mode: "char",
		input: String.fromCharCode(key),
		win: readwin});
	return false;
}
function sendinput()
{
	if (timer!=null) clearTimeout(timer);
	timer=null;
	if (!waiting) return false;
	waiting=false;
	var w=windows[readwin];
	var start=w.obj.innerHTML.length;
	w.obj.innerHTML+="<b>"+$('input').value+"</b><br />";
	var x=w.obj.innerHTML.length-start;
	w.pages.push(w.pages.pop()+x);
	w.pagelen+=x;
	call({	mode: "line",
		input: $('input').value,
		win: readwin});
	$('input').value='';
	return false;
}
function dolink(n,w)
{
	if (!linkwaiting) return false;
	call({	mode: "hyper",
		input: n,
		win: w});
	return false;
}
function sendtimeout()
{
	waiting=false;
	call({	mode: "timeout"});
	timer=null;
	return false;
}
function display(req)
{
	ins=eval('('+req.responseText+')');
	for (var i=0;i<ins.length;i++)
	{
		if (ins[i].c)
		{
			var w=windows[curwindow];
			var c=ins[i].c;
			var s=getstyle(w.type,w.style);
			if (w.type==4)
			{
				for (var x=0;x<c.length;x++)
				{
					var cc=c.charAt(x);
					if (cc=='&') cc='&amp;';
					if (cc=='<') cc='&lt;';
					if (cc=='>') cc='&gt;';
					if (inlink) cc="<a href='#' onclick='return dolink("+inlink+","+curwindow+")'>"+cc+"</a>";
					w.styles[w.y*w.width+w.x]=s;
					w.buffer[w.y*w.width+w.x++]=cc;
					if (w.x==w.width-1) { w.x=0; w.y++; if (w.y==w.height) w.y--; }
				}
			}
			else if (w.type==3)
			{
				c=c.replace(/&/g,'&amp;');
				c=c.replace(/</g,'&lt;');
				c=c.replace(/>/g,'&gt;');
				w.buffer+=s[0];
				w.buffer+=c;
				w.buffer+=s[1];
			}
			else alert("bad print w.type "+w.type);
			w.dirty=true;
		}
		else if (ins[i].e)
		{
			alert(ins[i].e);
		}
		else if (ins[i].z)
		{
			console.log(ins[i].z);
		}
		else switch(ins[i].m)
		{
			case 'readline':
				readwin=ins[i].w;
				if (ins[i].i[0])
				{
					$('input').value='';
					for (var j=0;ins[i].i[j];j++)
						$('input').value+=String.fromCharCode(ins[i].i[j]);
				}
				$('inputform').style.display="block";
				$('charinput').style.display="none";
				$('input').className=(timer!=null)?'timed':'';
				$('input').focus();
				waiting=true;
				break;
			case 'readchar':
				$('charinput').style.display="block";
				$('inputform').style.display="none";
				$('charinput').className=(timer!=null)?'timed':'';
				$('charinput').focus();
				readwin=ins[i].w;
				break;
			case 'xreadchar': //cancelled
				if (ins[i].w!=readwin) break;
				$('charinput').style.display="none";
				$('inputform').style.display="block";
				$('input').focus();
				break;
			case 'readlink':
				linkwaiting=true;
				break;
			case 'clearwin':
				var w=windows[ins[i].w];
				var s=getstyle(w.type,w.style);
				if (w.type==4)
				{
					for (var x=0;x<w.width*w.height;x++)
					{
						w.buffer[x]=((x%w.width)==w.width-1)?'\n':' ';
						w.styles[x]=s;
					}
					w.x=w.y=0;
				}
				else if (w.type==5)
				{
					w.obj.innerHTML='';
					w.obj.style.backgroundColor=w.bg;
				}
				else if (w.type==3)
				{
					w.obj.innerHTML=w.buffer='';
					while (w.pages.length) w.pages.shift();
					w.pagelen=0;
				}
				else alert("bad clear type "+w.type);
				w.dirty=true;
				break;
			case 'newline':
				var w=windows[curwindow];
				if (w.type==4)
				{
					w.x=0;
					w.y++;
					if (w.y==w.height) w.y--;
				}
				else if (w.type==3)
					w.buffer+="<br />";
				else alert("bad newline type "+w.type);
				w.dirty=true;
				break;
			case 'move':
				var w=windows[ins[i].w];
				if (w.type==4)
				{
					w.x=ins[i].x;
					w.y=ins[i].y;
					while (w.x>=w.width) { w.x-=w.width; w.y++; }
					if (w.y>=w.height) w.y=w.height-1;
				}
				break;
			case 'setstream':
				curwindow=ins[i].s;
				break;
			case 'stylehint':
				dostylehint(ins[i].w,ins[i].s,ins[i].h,ins[i].v);
				break;
			case 'style':
				windows[curwindow].style=ins[i].s;
				break;
			case 'close':
				closewindow(ins[i].w);
				break;
			case 'newwindow':
				newwindow(ins[i].i,ins[i].x,ins[i].y,ins[i].w,ins[i].h,ins[i].t);
				break;
			case 'resize':
				resizewindow(ins[i].i,ins[i].x,ins[i].y,ins[i].w,ins[i].h);
				break;
			case 'startlink':
				if (windows[curwindow].type==4) inlink=ins[i].v;
				else
				{
					if (ins[i].v==0)
						windows[curwindow].buffer+="</a>";
					else
						windows[curwindow].buffer+="<a href='#' onclick='return dolink("+ins[i].v+","+curwindow+")'>";
				}
				break;
			case 'timer':
				timer=setTimeout("sendtimeout()",ins[i].t);
				break;
			case 'setbackground':
				windows[ins[i].w].bg=ins[i].b;
				break;
			case 'fillrect':
				var w=windows[ins[i].i];
				pendingImages.push({style:ins[i].b,w:w,x:ins[i].x,y:ins[i].y,wd:ins[i].w,ht:ins[i].h,loaded:true});
				drawPending();
				break;
			case 'image':
				image(ins[i].i,ins[i].p,ins[i].x,ins[i].y,ins[i].w,ins[i].h);
				break;
			case 'quit':
				history.back();
				break;
			default: console.log(ins[i].m);
		}
	}
	for (i=0;i<windows.length;i++)
	{
		if (!windows[i] || !windows[i].dirty) continue;
		var w=windows[i];
		if (w.type==3)
		{
			var start=w.obj.innerHTML.length;
			w.obj.innerHTML+=windows[i].buffer;
			var pgraph=w.obj.innerHTML.length-start;
			w.buffer='';
			if (pgraph>0)
			{
				w.pages.push(pgraph);
				w.pagelen+=pgraph;
			}
			while (w.pagelen>5000)
			{
				pgraph=w.pages.shift();
				w.pagelen-=pgraph;
				w.obj.innerHTML=w.obj.innerHTML.substring(pgraph);
			}
			w.obj.scrollTop=w.obj.scrollHeight;
		}
		else if (w.type==4)
		{
			var prevstyle=['',''];
			var out='';
			for (var s=0;s<w.styles.length;s++)
			{
				if (w.styles[s][0]!=prevstyle[0])
				{
					out+=prevstyle[1];
					out+=w.styles[s][0];
					prevstyle=w.styles[s];
				}
				out+=w.buffer[s];
			}
			out+=prevstyle[1];
			w.obj.innerHTML=out;
		}
		w.dirty=false;
	}
}

function newwindow(win,x,y,width,height,type)
{
	var w=new Object();
	w.type=type;
	w.dirty=false;
	w.style=0;
	windows[win]=w;
	if (type==3)
	{
		w.obj=$('screen').appendChild(document.createElement('div'));
		w.buffer='';
		w.pages=[];
		w.pagelen=0;
	}
	else if (type==4)
	{
		w.obj=$('screen').appendChild(document.createElement('pre'));
		w.width=(width/font4width|0)+1;
		w.height=height/font4height|0;
		w.buffer=new Array(w.width*w.height);
		w.styles=new Array(w.width*w.height);
		for (var i=0;i<w.width*w.height;i++)
		{
			w.buffer[i]=((i%w.width)==w.width-1)?'\n':' ';
			w.styles[i]=['',''];
		}
		w.x=0;
		w.y=0;
	}
	else if (type==5) //graphics window. Used by Dead Cities
	{
		w.obj=$('screen').appendChild(document.createElement('canvas'));
		w.bg="#ffffff";
		w.obj.width=width;
		w.obj.height=height;
	}
	else alert("unknown window type "+type);
	w.obj.style.position="absolute";
	w.obj.style.left=x+"px";
	w.obj.style.top=y+"px";
	if (type!=5)
	{
		w.obj.style.width=width+"px";
		w.obj.style.height=height+"px";
	}
}
function closewindow(win)
{
	$('screen').removeChild(windows[win].obj);
	delete windows[win].obj;
	windows[win].dirty=false;
	if (win==curwindow) curwindow=0;
	if (win==readwin) readwin=0;
}
function resizewindow(win,x,y,width,height)
{
	w=windows[win];
	if (w.type==4)
	{
		w.width=(width/font4width|0)+1;
		w.height=height/font4height|0;
		w.buffer=new Array(w.width*w.height);
		w.styles=new Array(w.width*w.height);
		var s=getstyle(w.type,w.style);
		for (var i=0;i<w.width*w.height;i++)
		{
			w.buffer[i]=((i%w.width)==w.width-1)?'\n':' ';
			w.styles[i]=s;
		}
		w.x=0;
		w.y=0;
	}
	else if (w.type==5)
	{
		w.obj.style.backgroundColor=w.bg;
		w.obj.width=width;
		w.obj.height=height;
	}
	w.obj.style.left=x+"px";
	w.obj.style.top=y+"px";
	if (w.type!=5)
	{
		w.obj.style.width=width+"px";
		w.obj.style.height=height+"px";
	}
	w.dirty=true;
}
function dostylehint(w,s,h,v)
{
	if (!stylehints[w]) stylehints[w]=[];
	if (!stylehints[w][s]) stylehints[w][s]=[];
	stylehints[w][s][h]=v;
}
function getstyle(w,s)
{
	var open='',close='',fore='#000000',back='#ffffff';
	if (stylehints[w] && stylehints[w][s])
	{
		s=stylehints[w][s];
		if (s[0]) open+='margin-left:'+s[0]+';';
		if (s[3]) open+='font-size:'+(10+s[3])+'pt;';
		if (s[4] && s[4]==1) open+='font-weight:bold;';
		if (s[5]) open+='font-style:italic;';
		if (s[6] && s[6]!=1)  open+='font-family:"Courier New",monospace;white-space:pre;';
		if (s[7] && s[7]!='') fore=s[7];
		if (s[8] && s[8]!='') back=s[8];
		if (s[9]) { var t=fore; fore=back; back=t; }
	}
	if (fore!='#000000') open+='color:'+fore+';';
	if (back!='#ffffff') open+='background-color:'+back+';';
	if (open)
	{
		open='<span style="'+open+'">';
		close='</span>';
	}
	return [open,close];
}
var imgaligns=['','baseline','top','absmiddle','left','right'];
function image(win,image,x,y,wd,ht)
{
	var w=windows[win];
	var src=imgadapter+'?game='+escape(curgame)+'&picture='+escape(image);
	if (w.type==3)
	{
		w.buffer+='<img src="'+src+'" align="'+imgaligns[x]+'"';
		if (wd) w.buffer+=' width="'+wd+'" height="'+ht+'"';
		w.buffer+=' />';
	}
	else if (w.type==5)
	{
		var img=new Image();
		pendingImages.push({img:img,x:x,y:y,w:w,wd:wd,ht:ht,loaded:false});
		img.onload=function(){
			for (var i=0;i<pendingImages.length;i++)
				if (pendingImages[i].img==img)
				{
					pendingImages[i].loaded=true;
					break;
				}
			drawPending();
		}
		img.src=src;
	}
}
function drawPending()
{
	while (pendingImages.length)
	{
		if (!pendingImages[0].loaded) return;
		var p=pendingImages.shift();
		var ctx=p.w.obj.getContext('2d');
		if (p.img)
		{
			if (p.wd) ctx.drawImage(p.img,p.x,p.y,p.wd,p.ht);
			else ctx.drawImage(p.img,p.x,p.y);
		}
		else
		{
			ctx.fillStyle=p.style;
			ctx.fillRect(p.x,p.y,p.wd,p.ht);
		}
	}
}
